/**
 * <p>Title: com.szedi.common.util.StringUtil.java</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2005</p>
 * <p>Company: col</p>
 */
package com.googlecode.cswish.util;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;


/**
 * A simple util class
 * 
 * @author Jerry.Feng date 2005-7-9 13:42:26
 */
public class StringUtil {
	
	public static String[] split(String s, char c) {
		if (s == null) {
			return null;
		}
		
		List<String> list = splitToList(s, c);
		String[] array = new String[list.size()];
		list.toArray(array);
		return array;
	}

	public static List<String> splitToList(String s, char c) {
		if (s == null) {
			return null;
		}
		
		int len = s.length();
		List<String> list = new ArrayList<String>();
		int begin = 0;
		for (int i = 0; i < len; i++) {
			if (s.charAt(i) == c) {
				list.add(s.substring(begin, i));
				begin = i + 1;
			}
		}
		if (begin < len) {
			list.add(s.substring(begin));
		}
		return list;
	}
	
	public static String replaceSpecialChar(String value) {
		if (value == null) {
			return null;
		}

		char [] cs = value.toCharArray();
		char [] buff = new char[cs.length];
		
		for (int i = 0; i < cs.length; i++) {
			char c = cs[i];
			if (c == '[') {
				c = '<';
			} else if (c == ']') {
				c = '>';
			} else if (c == '.'){
				c = '*';
			}
			
			buff[i] = c;
		}
		
		return new String(buff);
	}

	public static String restoreSpecialChar(String value) {
		if (value == null) {
			return null;
		}

		char [] cs = value.toCharArray();
		char [] buff = new char[cs.length];
		
		for (int i = 0; i < cs.length; i++) {
			char c = cs[i];
			if (c == '<') {
				c = '[';
			} else if (c == '>') {
				c = ']';
			} else if (c == '*'){
				c = '.';
			}
			
			buff[i] = c;
		}
		
		return new String(buff);
	}
	
	public static String remove(String value, char c) {
		int len = value.length();
		StringBuffer sb = new StringBuffer(len);
		for (int i = 0; i < len; i++) {
			char tmp = value.charAt(i);
			if (tmp != c) {
				sb.append(tmp);
			}
		}
		return sb.toString();
	}
	
	public static String notNull(String str) {
		return str == null ? "" : str;
	}
	
	public static boolean equals(String s1, String s2) {
		return s1 == null && s2 == null || s1 != null && s1.equals(s2);
	}
	
	/**
	 * A structure to store the mapping property of group property
	 */
	public static class MappingProperty extends HashMap {
		
		private String mapping;
		
		public MappingProperty(String mapping) {
			super(0);
			
			this.mapping = mapping;
		}
		
		public String getMapping() {
			return mapping;
		}
	}
	
	/**
	 * Group the plain property list to tree structure, the leaf node is empty map
	 * 
	 * @param properties
	 * @return
	 */
	// <key, sub keys>
	public static Map<String, Map> groupProperties(String[] properties, boolean treatExFuncAsWholeProperty) {
		Map<String, Map> group = new HashMap<String, Map>();
		
		for (String property : properties) {
			// special logic for extra property, treat it as a whole property -- ':func.p1.p2'
			String realProperty = null;
			if (property.charAt(0) == ':') {
				if (treatExFuncAsWholeProperty) {
					group.put(property, Collections.EMPTY_MAP);
					continue;
				}
				
				realProperty = property;
				
				// format the property name, see functions.val()
				int index = property.indexOf('.', 1);
				if (index > 0) {
					int end = property.indexOf('(', index + 1);
					if (end == -1) {
						property = property.substring(index + 1);
					} else {
						property = property.substring(index + 1, end);
					}
				}
			}
			
			String[] shortNames = StringUtils.split(property, '.');
			
			Map<String, Map> container = group;
			for (int i = 0, maxIndex = shortNames.length - 1; i <= maxIndex; i++) {
				String shortName = shortNames[i];
				Map existed = container.get(shortName);
				if (existed == null) {
					if (i == maxIndex) {
						if (realProperty != null) {
							existed = new MappingProperty(realProperty);
						} else {
							existed = new HashMap<>(0);
						}
					} else {
						existed = new HashMap<String, Map>();
					}
					container.put(shortName, existed);
				}
				container = existed;
			}
		}
		
		return group;
	}
	
	public static String replace(String str, String var, String[] replacements) {
		StringBuilder sb = new StringBuilder();
		int index = str.indexOf(var);
		int lastIndex = 0;
		int i = 0;
		while (index > 0 && i < replacements.length) {
			sb.append(str.substring(lastIndex, index));
			sb.append(replacements[i]);
			lastIndex = index + var.length();
			index = str.indexOf(var, lastIndex);
			i++;
		}
		if (lastIndex < str.length()) {
			sb.append(str.substring(lastIndex));
		}
		return sb.toString();
	}
	
	public static boolean startsWith(StringBuilder sb, String prefix) {
		if (sb == null || prefix == null) {
			return false;
		}
		if (sb.length() < prefix.length()) {
			return false;
		}
		
		for (int i = 0, len = prefix.length(); i < len; i++) {
			char c1 = prefix.charAt(i);
			char c2 = sb.charAt(i);
			if (c1 != c2) {
				return false;
			}
		}
		return true;
	}
	
	public static String removeEscapeChar(String str) {
		if (str == null) {
			return null;
		}
		
		int index = str.indexOf('\\');		// fast check
		if (index == -1) {
			return str;
		}
		
		StringBuilder sb = new StringBuilder(str.length());
		int lastIndex = 0;
		while (index > 0) {
			sb.append(str.substring(lastIndex, index));
			
			lastIndex = index + 1;	// skip current '\'
			index = str.indexOf('\\', lastIndex + 1);	// 'lastIndex + 1' ==> don't check the next char
		}
		if (lastIndex < str.length()) {
			sb.append(str.substring(lastIndex));
		}
		return sb.toString();
	}
	
	// s1.startsWith(s2);
	public static boolean startsWithSkipFileSeparator(String s1, String s2) {
		int len1 = s1.length();
		int len2 = s2.length();
		if (len1 < len2) {
			return false;
		}
		
		for (int i = 0; i < len2; i++) {
			char c = s1.charAt(i);
			if (c == File.separatorChar) {
				continue;
			}
			
			if (c != s2.charAt(i)) {
				return false;
			}
		}
		return true;
	}
}
